<template>
  <div class="page" @touchstart="onStart" @touchmove="onMove" @touchend="onEnd">
    <div class="box">
      <div class="box-page" :style="front.style">
        <div class="box-front">
          正面1 正面2 正面3 正面4 正面5 正面6 正面7 正面8 正面9 正面10 正面11 正面12 正面13
        </div>
      </div>
      <div class="box-page" :style="back.style">
        <div class="box-back">
          反面1 反面2 反面3 反面4 反面5 反面6 反面7 反面8 反面9 反面10 反面11 反面12 反面13 反面
        </div>
      </div>
    </div>
    <div class="box1"></div>
    <button @click="step1">状态1</button>
    <button @click="step11">状态1_1</button>
    <button @click="step2">状态2</button>
    <button @click="step3">状态3</button>
    <button @click="step31">状态3_1</button>
    <button @click="step32">状态3_2</button>
    <button @click="step4">状态4</button>
    <button @click="step5">状态5</button>
    <button @click="step51">状态5_1</button>
    <button @click="step6">状态6</button>
    <button @click="step7">动态从左到右</button>
    <button @click="step8">动态从右到左</button>
  </div>
</template>
<script>
import { mat4, vec2, vec3 } from '../../libs/glmatrix/gl-matrix-min.js'
import { Tween, Easing } from '@tweenjs/tween.js'
export default {
  data() {
    return {
      direction: 0, //0正向 1反向
      front: {
        style: {},
        m: [],
        clip: [],
        z: 0 //0正面 1反面
      },
      back: {
        style: {},
        m: [],
        clip: [],
        z: 1
      },
      now: []
    }
  },
  methods: {
    reset() {},
    buildStyle(obj) {
      let { w, h } = this
      let m = this.getMat(obj.m, obj.z)
      let style = {}
      let transform = `matrix3d(${m.join(',')})`
      style.transform = transform

      let clip = obj.clip
        .map((res) => {
          let [x, y] = res
          return [x + w / 2, y + h / 2]
        })
        .map((res) => {
          let [x, y] = res
          return x + 'px' + ' ' + y + 'px'
        })
      style['clip-path'] = `polygon(${clip.join(',')})`
      obj.style = style
    },
    resetLeft() {
      console.log(`重置到左边`)
      this.direction = 0
      let m = mat4.create()
      mat4.translate(m, m, [50, 0, 0])
      this.front.m = [m]
      this.back.m = [m]
      this.build([100, -50, 0], [100, -50, 0])
    },
    resetRight() {
      console.log(`重置到右边`)
      this.direction = 1
      let m = mat4.create()
      mat4.scale(m, m, [-1, 1, 1])
      mat4.translate(m, m, [50, 0, 0])
      this.front.m = [m]
      this.back.m = [m]
      this.build([-100, -50, 0], [-100, -50, 0])
    },
    step1() {
      this.resetLeft()
    },
    step11() {
      let m = mat4.create()
      mat4.translate(m, m, [50, 0, 0])
      this.front.m = [m]
      this.back.m = [m]
      this.buildStyle(this.front)
      this.buildStyle(this.back)
      this.build([100, -40, 0], [100, -50, 0])
    },
    step2() {
      this.resetRight()
    },
    buildLt(s0, e0) {
      let { w, h } = this
      let x = (s0[0] + e0[0]) / 2
      let y = (s0[1] + e0[1]) / 2
      let center = [x, y, 0]

      let k1 = (e0[1] - s0[1]) / (e0[0] - s0[0])
      let k2 = -1 / k1

      let b = y - k2 * center[0]
      let k2line_y = (x) => {
        return k2 * x + b
      }
      let k2line_x = (y) => {
        return (y - b) / k2
      }

      //上边界 y = -h / 2
      let m_top = [k2line_x(-h / 2), -h / 2]
      //右边界 x = w / 2
      let m_right = [w / 2, k2line_y(w / 2)]
      //左边界 x = -w / 2
      let m_left = [-w / 2, k2line_y(-w / 2)]
      //下边界 y = h / 2
      let m_bottom = [k2line_x(h / 2), h / 2]

      let clip_front = []
      let clip_back = []
      let { lt, lb, rt, rb } = this.corrds
      if (m_right[1] > h / 2) {
        clip_front = [lt, m_top, m_bottom, lb]
        clip_back = [m_top, rt, rb, m_bottom]
      } else {
        clip_front = [lt, m_top, m_right, rb, lb]
        clip_back = [m_top, rt, m_right]
      }

      if (this.direction == 0) {
        this.front.clip = clip_front
        this.back.clip = clip_back
      } else {
        this.front.clip = clip_back
        this.back.clip = clip_front
      }

      //对称操作
      let axis1 = [1, 0, 0]
      let axis2 = vec3.create()

      vec2.sub(axis2, e0, s0)
      let cross = vec3.create()
      let angle = vec3.angle(axis1, axis2)
      vec3.cross(cross, axis1, axis2)
      let deg = (angle / Math.PI) * 180
      console.log(deg, cross, axis1, axis2)
      if (cross[2] < 0) {
        angle = -angle
      }

      let m = mat4.create()
      //平移原点
      let m1 = mat4.create()
      mat4.translate(m1, m1, center)
      //旋转角度
      let m2 = mat4.create()
      mat4.rotateZ(m2, m2, angle)
      let m3 = mat4.create()
      mat4.mul(m3, m1, m2)
      let m3_i = mat4.create()
      mat4.invert(m3_i, m3)
      //对称
      let m4 = mat4.create()
      mat4.scale(m4, m4, [-1, 1, 1])

      mat4.mul(m, m, m3)
      mat4.mul(m, m, m4)
      mat4.mul(m, m, m3_i)
      if (this.direction == 0) {
        this.back.m.push(m)
      } else {
        this.front.m.push(m)
      }

      this.buildStyle(this.front)
      this.buildStyle(this.back)
    },
    fix_point_in_range(s0, e0) {
      let v1 = vec3.create()
      vec3.sub(v1, e0, s0)
      let v2 = [0, e0[1], 0]
      let angle = vec3.angle(v1, v2)
      let cross = vec3.create()
      vec3.cross(cross, v1, v2)
      let deg = (angle / Math.PI) * 180
      console.log(`deg`, deg, 'v1', v1, 'cross', cross)
      let x, y
      if (deg < 45) {
        if (e0[1] < 0) {
          x = e0[0] + v1[1] //这里有很大问题，方向错误，需要先判断
        } else {
          x = e0[0] - v1[1] //这里有很大问题，方向错误，需要先判断
        }
        y = s0[1]
      } else {
        x = s0[0]
        y = s0[1]
      }
      return {
        s1: [x, y],
        e1: e0
      }
    },
    buildCommon(s0, e0) {
      this.now = {
        s: {
          x: s0[0],
          y: s0[1],
          z: s0[2]
        },
        e: {
          x: e0[0],
          y: e0[1],
          z: e0[2]
        }
      }
      let diff = vec3.create()
      vec3.sub(diff, e0, s0)
      this.diff = diff

      let { w, h } = this
      let x = (s0[0] + e0[0]) / 2
      let y = (s0[1] + e0[1]) / 2
      let center = [x, y, 0]

      //先处理范围，限定范围，在处理特殊情况
      let k1, k2, b, k2line_x, k2line_y
      //y轴相同
      k1 = (e0[1] - s0[1]) / (e0[0] - s0[0])
      k2 = -1 / k1

      b = y - k2 * center[0]
      k2line_y = (x) => {
        return k2 * x + b
      }
      k2line_x = (y) => {
        return (y - b) / k2
      }

      //上边界 y = -h / 2
      let m_top, m_right, m_left, m_bottom
      if (k1 == 0) {
        m_top = [center[0], -h / 2]
        m_bottom = [center[0], h / 2]
      } else {
        m_top = [k2line_x(-h / 2), -h / 2]
        //右边界 x = w / 2
        m_right = [w / 2, k2line_y(w / 2)]
        //左边界 x = -w / 2
        m_left = [-w / 2, k2line_y(-w / 2)]
        //下边界 y = h / 2
        m_bottom = [k2line_x(h / 2), h / 2]
      }

      let clip_front = []
      let clip_back = []
      let { lt, lb, rt, rb } = this.corrds
      if (s0[0] == e0[0] && s0[1] == e0[1]) {
        clip_front = [lt, lb, rb, rt]
        clip_back = [lt, lt, lt, lt]
      } else {
        if (!m_right || m_right[1] < -h / 2 || m_right[1] > h / 2) {
          clip_front = [lt, m_top, m_bottom, lb]
          clip_back = [m_top, rt, rb, m_bottom]
        } else {
          if (m_top[0] > w / 2) {
            //这里有区别
            clip_front = [lt, rt, m_right, m_bottom, lb]
            clip_back = [m_right, rb, m_bottom]
          } else {
            clip_front = [lt, m_top, m_right, rb, lb]
            clip_back = [m_top, rt, m_right]
          }
        }
      }

      if (this.direction == 0) {
        this.front.clip = clip_front
        this.back.clip = clip_back
      } else {
        this.front.clip = clip_back
        this.back.clip = clip_front
      }
      if (s0[0] == e0[0] && s0[1] == e0[1]) {
      } else {
        //对称操作
        let axis1 = [1, 0, 0]
        let axis2 = vec3.create()

        vec2.sub(axis2, e0, s0)
        let cross = vec3.create()
        let angle = vec3.angle(axis1, axis2)
        vec3.cross(cross, axis1, axis2)
        let deg = (angle / Math.PI) * 180
        //console.log(deg, cross, axis1, axis2)
        if (cross[2] < 0) {
          angle = -angle
        }

        let m = mat4.create()
        //平移原点
        let m1 = mat4.create()
        mat4.translate(m1, m1, center)
        //旋转角度
        let m2 = mat4.create()
        mat4.rotateZ(m2, m2, angle)
        let m3 = mat4.create()
        mat4.mul(m3, m1, m2)
        let m3_i = mat4.create()
        mat4.invert(m3_i, m3)
        //对称
        let m4 = mat4.create()
        mat4.scale(m4, m4, [-1, 1, 1])

        mat4.mul(m, m, m3)
        mat4.mul(m, m, m4)
        mat4.mul(m, m, m3_i)
        if (this.direction == 0) {
          this.back.m[1] = m
        } else {
          this.front.m[1] = m
        }
      }
      this.buildStyle(this.front)
      this.buildStyle(this.back)
    },
    buildLb(s0, e0) {
      let { w, h } = this
      let x = (s0[0] + e0[0]) / 2
      let y = (s0[1] + e0[1]) / 2
      let center = [x, y, 0]

      let k1 = (e0[1] - s0[1]) / (e0[0] - s0[0])
      let k2 = -1 / k1

      let b = y - k2 * center[0]
      let k2line_y = (x) => {
        return k2 * x + b
      }
      let k2line_x = (y) => {
        return (y - b) / k2
      }

      //上边界 y = -h / 2
      let m_top = [k2line_x(-h / 2), -h / 2]
      //右边界 x = w / 2
      let m_right = [w / 2, k2line_y(w / 2)]
      //左边界 x = -w / 2
      let m_left = [-w / 2, k2line_y(-w / 2)]
      //下边界 y = h / 2
      let m_bottom = [k2line_x(h / 2), h / 2]

      let clip_front = []
      let clip_back = []
      let { lt, lb, rt, rb } = this.corrds
      if (m_right[1] < -h / 2) {
        clip_front = [lt, m_top, m_bottom, lb]
        clip_back = [m_top, rt, rb, m_bottom]
      } else {
        //这里有区别
        clip_front = [lt, rt, m_right, m_bottom, lb]
        clip_back = [m_right, rb, m_bottom]
      }

      if (this.direction == 0) {
        this.front.clip = clip_front
        this.back.clip = clip_back
      } else {
        this.front.clip = clip_back
        this.back.clip = clip_front
      }

      //对称操作
      let axis1 = [1, 0, 0]
      let axis2 = vec3.create()

      vec2.sub(axis2, e0, s0)
      let cross = vec3.create()
      let angle = vec3.angle(axis1, axis2)
      vec3.cross(cross, axis1, axis2)
      let deg = (angle / Math.PI) * 180
      //console.log(deg, cross, axis1, axis2)
      if (cross[2] < 0) {
        angle = -angle
      }

      let m = mat4.create()
      //平移原点
      let m1 = mat4.create()
      mat4.translate(m1, m1, center)
      //旋转角度
      let m2 = mat4.create()
      mat4.rotateZ(m2, m2, angle)
      let m3 = mat4.create()
      mat4.mul(m3, m1, m2)
      let m3_i = mat4.create()
      mat4.invert(m3_i, m3)
      //对称
      let m4 = mat4.create()
      mat4.scale(m4, m4, [-1, 1, 1])

      mat4.mul(m, m, m3)
      mat4.mul(m, m, m4)
      mat4.mul(m, m, m3_i)
      if (this.direction == 0) {
        this.back.m.push(m)
      } else {
        this.front.m.push(m)
      }

      this.buildStyle(this.front)
      this.buildStyle(this.back)
    },

    build(s, e) {
      let s0 = this.getOriginPoint(s, this.front.m)
      let e0 = this.getOriginPoint(e, this.front.m)

      console.log('s', s, s0)
      console.log('e', e, e0)

      /*
      //情况1 e0为左上角
      if (e0[1] < 0 && e0[0] > 0) {
        this.buildLt(s0, e0)
      } else {
        //情况2 e0为左下角
        this.buildLb(s0, e0)
      }
      */

      let [sx, sy] = s0
      let [ex, ey] = e0
      let s2, e2
      if (ex > 0 && ey > 0) {
        sx = sx > ex ? ex : sx
        sy = sy > ey ? ey : sy
        e2 = this.corrds.rb
      }
      if (ex > 0 && ey < 0) {
        sx = sx > ex ? ex : sx
        sy = sy < ey ? ey : sy
        e2 = this.corrds.rt
      }
      if (ex < 0 && ey > 0) {
        sx = sx < ex ? ex : sx
        sy = sy > ey ? ey : sy
        e2 = this.corrds.lb
      }
      if (ex < 0 && ey < 0) {
        sx = sx < ex ? ex : sx
        sy = sy < ey ? ey : sy
        e2 = this.corrds.lt
      }
      s0 = [sx, sy, 0]
      let diff = vec3.create()
      vec3.sub(diff, e0, s0)
      s2 = vec3.create()
      vec2.sub(s2, e2, diff)

      console.log('s2', s2)
      console.log('e2', e2)

      //统一解法
      let { s1, e1 } = this.fix_point_in_range(s2, e2)
      this.buildCommon(s1, e1)
    },
    step3() {
      this.direction = 0
      this.step1()
      let s = [50, 0, 0]
      let e = [100, -50, 0]
      this.build(s, e)
    },
    //垂直水平的情况
    step31() {
      this.direction = 0
      this.step1()
      let s = [50, -50, 0]
      let e = [100, -50, 0]
      this.build(s, e)
    },
    //垂直水平的情况
    step32() {
      this.direction = 0
      this.step1()
      let s = [80, 0, 0]
      let e = [100, -50, 0]
      this.build(s, e)
    },
    step4() {
      this.direction = 1
      this.step2()
      let s = [-50, 0, 0]
      let e = [-100, -50, 0]
      this.build(s, e)
    },
    step5() {
      this.direction = 0
      this.step1()
      let s = [50, 0, 0]
      let e = [100, 50, 0]
      this.build(s, e)
    },
    //垂直水平的情况
    step51() {
      this.direction = 0
      this.step1()
      let s = [90, 0, 0]
      let e = [100, 50, 0]
      this.build(s, e)
    },

    step6() {
      this.direction = 1
      this.step2()
      let s = [-50, 0, 0]
      let e = [-100, 50, 0]
      this.build(s, e)
    },
    //从左往右
    step7() {
      let isStop = false
      this.direction = 0
      let e = this.now.e
      let s = Object.assign({}, this.now.s)
      const tween = new Tween(s, false)
        .to(
          {
            x: -100,
            y: e.y,
            z: 0
          },
          300
        )
        .easing(Easing.Quadratic.InOut)
        .onUpdate(() => {
          this.build([s.x, s.y, s.z], [e.x, e.y, e.z])
        })
        .onComplete(() => {
          console.log(s, e)
          isStop = true
          this.resetRight()
        })
        .start()
      // Setup the animation loop.
      function animate(time) {
        if (!isStop) {
          tween.update(time)
          requestAnimationFrame(animate)
        }
      }
      requestAnimationFrame(animate)
    },
    //从右到左
    step8() {
      this.direction = 1
      let isStop = false
      let e = this.now.e
      let s = Object.assign({}, this.now.s)
      const tween = new Tween(s, false)
        .to(
          {
            x: 100,
            y: e.y,
            z: 0
          },
          300
        )
        .easing(Easing.Quadratic.InOut)
        .onUpdate(() => {
          this.build([s.x, s.y, s.z], [e.x, e.y, e.z])
        })
        .onComplete(() => {
          console.log(s, e)
          isStop = true
          this.resetLeft()
        })
        .start()
      // Setup the animation loop.
      function animate(time) {
        if (!isStop) {
          tween.update(time)
          requestAnimationFrame(animate)
        }
      }
      requestAnimationFrame(animate)
    },
    getMat(mList, z = 0) {
      let m = mat4.create()
      mList.forEach((res) => {
        mat4.mul(m, m, res)
      })
      if (this.direction == 0) {
        mat4.translate(m, m, [0, 0, z])
      } else {
        mat4.translate(m, m, [0, 0, 1 - z])
      }
      return m
    },
    getOriginPoint(nowPoint, matList) {
      let m = mat4.create()
      let nowMat = matList[0]
      let invert_mat = mat4.create()
      mat4.invert(invert_mat, nowMat)
      let v = vec3.create()
      vec3.transformMat4(v, nowPoint, invert_mat)
      return v
    },
    init() {
      this.corrds = {
        lt: [-50, -50, 0],
        lb: [-50, 50, 0],
        rt: [50, -50, 0],
        rb: [50, 50, 0],
        origin: [0, 0, 0]
      }
      this.ww = window.innerWidth
      this.wh = window.innerHeight
      this.w = 100
      this.h = 100
    },
    onStart(e) {
      if (this.isStart) return
      let spoint = this.getPoint(e)
      if (spoint[0] > 0 && this.direction == 0) {
        this.resetLeft()
        this.isStart = true
      } else if (spoint[0] < 0 && this.direction == 1) {
        this.resetRight()
        this.isStart = true
      }
      this.s_point = spoint
    },
    getPoint(e) {
      let { x, y } = e.target.getBoundingClientRect()
      let [touch] = e.touches
      //console.log(touch)
      let { clientX, clientY } = touch
      let point = [clientX - this.ww / 2, clientY - 150, 0]
      return point
    },
    getEndPoint(s_point) {
      let corrds = {
        rt: [100, -50, 0],
        lt: [-100, -50, 0],
        rb: [100, 50, 0],
        lb: [-100, 50, 0]
      }
      let { ww, wh } = this
      let [x, y] = s_point
      x = x - ww / 2
      y = y - wh / 2
      if (x < 0 && y < 0) {
        return {
          type: 'lt',
          direction: 1,
          point: corrds.lt
        }
      }
      if (x >= 0 && y <= 0) {
        return {
          type: 'rt',
          direction: 0,
          point: corrds.rt
        }
      }
      if (x < 0 && y > 0) {
        return {
          type: 'lb',
          direction: 1,
          point: corrds.lb
        }
      }
      if (x > 0 && y > 0) {
        return {
          type: 'rb',
          direction: 0,
          point: corrds.rb
        }
      }
    },
    onMove(e) {
      if (this.isStart) {
        //console.log(e)
        let mp = this.getPoint(e)
        //console.log(mp)
        //let { s_point } = this
        //let diff = [mp[0] - s_point[0], mp[1] - s_point[1], 0]
        //let s = vec3.create()
        //let { point, direction, type } = this.es
        //if (type == 'rt') {
        //let [dx, dy] = diff
        //console.log(`dx,dy`, dx, dy, 'type', type)
        //dx = dx > 0 ? 0 : dx
        //dy = dy < 0 ? 0 : dy
        //diff = [dx, dy, 0]
        //}
        //if (type == 'rb') {
        //let [dx, dy] = diff
        //console.log(`dx,dy`, dx, dy, 'type', type)
        //dx = dx > 0 ? 0 : dx
        //dy = dy > 0 ? 0 : dy
        //diff = [dx, dy, 0]
        //}
        //if (type == 'lt') {
        //let [dx, dy] = diff
        //console.log(`dx,dy`, dx, dy, 'type', type)
        //dx = dx < 0 ? 0 : dx
        //dy = dy < 0 ? 0 : dy
        //diff = [dx, dy, 0]
        //}
        //if (type == 'lb') {
        //let [dx, dy] = diff
        //console.log(`dx,dy`, dx, dy, 'type', type)
        //dx = dx < 0 ? 0 : dx
        //dy = dy > 0 ? 0 : dy
        //diff = [dx, dy, 0]
        //}
        //console.log(`diff`, diff)
        //vec3.add(s, point, diff)
        //console.log(s, point, 'onMove')
        //this.diff = diff
        this.build(mp, this.s_point)
      }
    },
    leftToRight(direction) {
      let isStop = false
      this.direction = 0
      let e = this.now.e
      let s = Object.assign({}, this.now.s)
      const tween = new Tween(s, false)
        .to(
          {
            x: direction == 0 ? 50 : -150,
            y: e.y,
            z: 0
          },
          300
        )
        .easing(Easing.Quadratic.InOut)
        .onUpdate(() => {
          console.log(`update`, s, e)
          this.buildCommon([s.x, s.y, s.z], [e.x, e.y, e.z])
        })
        .onComplete(() => {
          console.log(s, e)
          isStop = true
          if (direction == 0) {
            this.resetLeft()
          } else {
            this.resetRight()
          }
        })
        .start()
      // Setup the animation loop.
      function animate(time) {
        if (!isStop) {
          tween.update(time)
          requestAnimationFrame(animate)
        }
      }
      requestAnimationFrame(animate)
    },
    rightToLeft(direction) {
      this.direction = 1
      let isStop = false
      let e = this.now.e
      let s = Object.assign({}, this.now.s)
      const tween = new Tween(s, false)
        .to(
          {
            x: direction == 0 ? 50 : -150,
            y: e.y,
            z: 0
          },
          300
        )
        .easing(Easing.Quadratic.InOut)
        .onUpdate(() => {
          this.buildCommon([s.x, s.y, s.z], [e.x, e.y, e.z])
        })
        .onComplete(() => {
          console.log(s, e)
          isStop = true
          if (direction == 0) {
            this.resetRight()
          } else {
            this.resetLeft()
          }
        })
        .start()
      // Setup the animation loop.
      function animate(time) {
        if (!isStop) {
          tween.update(time)
          requestAnimationFrame(animate)
        }
      }
      requestAnimationFrame(animate)
    },
    onEnd(e, options) {
      console.log(`999999`)
      let { w } = this
      if (this.isStart) {
        if (this.direction == 0) {
          let [dx] = this.diff
          if (Math.abs(dx) < w / 2) {
            this.leftToRight(0)
          } else {
            this.leftToRight(1)
          }
        }
        if (this.direction == 1) {
          let [dx] = this.diff
          debugger
          if (Math.abs(dx) < w / 2) {
            this.rightToLeft(0)
          } else {
            this.rightToLeft(1)
          }
        }
        this.isStart = false
      }
    }
  },
  mounted() {
    this.init()
  }
}
</script>
<style type="text/css" lang="scss">
.page {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
.box {
  width: 100px;
  height: 100px;
  border: 1px solid #000;
  position: relative;
  transform-style: preserve-3d;
  margin: 100px auto;
  box-sizing: border-box;
  &-page {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
  }
  &-front {
    background: grey;
    width: 100px;
    height: 100px;
    overflow: hidden;
  }
  &-back {
    background: #646495;
    transform: scale(-1, 1);
    width: 100px;
    height: 100px;
    overflow: hidden;
  }
}
.box1 {
  width: 100px;
  height: 100px;
  border: 1px solid #000;
  transform: translate(10px, 0) rotate(30deg) scale(1.5, 1);
  clip-path: polygon(0 0, 50px 0, 50px 50px, 0 50px);
}
body {
  margin: 0;
}
</style>
